/* ========================================================================== */
/*                                                                            */
/*   AM29LV033C_FLASH.c                                                               */
/*   (c) 2001 Author                                                          */
/*                                                                            */
/*   Description                                                              */
/*                                                                            */
/* ========================================================================== */
#include "boardtest.h"

static Uint16 buffer[256];

/* Read an 8-bit value from a CPLD register */
Uint8 EVMDM642_rget(Int16 regnum)
{
    Uint8 *pdata;
    
    /* Return lower 8 bits of register */
    pdata = (Uint8 *)(EVMDM642_CPLD_BASE + regnum);
    return (*pdata & 0xff);
}

/* Write an 8-bit value to a CPLD register */
void EVMDM642_rset(Int16 regnum, Uint8 regval)
{
    Uint8 *pdata;
    
    /* Write lower 8 bits of register */
    pdata = (Uint8 *)(EVMDM642_CPLD_BASE + regnum);
    *pdata = (regval & 0xff);
}

/* Spin in a delay loop for delay iterations */
void EVMDM642_wait(Uint32 delay)
{
    volatile Uint32 i, n;
    
    n = 0;
    for (i = 0; i < delay; i++)
    {
        n = n + 1;
    }
}

/* Spin in a delay loop for delay microseconds */
void EVMDM642_waitusec(Uint32 delay)
{
    EVMDM642_wait(delay * 21);
}


/* Read data from a data range in Flash */
void EVMDM642_FLASH_read(Uint32 src, Uint32 dst, Uint32 length)
{
    Uint8 *psrc, *pdst;
    Uint32 i;
    
    /* Establish source and destination */
    psrc = (Uint8 *)src;
    pdst = (Uint8 *)dst;
    for (i = 0; i < length; i++)
    {
        *pdst++ = *psrc++;
    }
}

/* Write data to a data range in Flash */
void EVMDM642_FLASH_write(Uint32 src, Uint32 dst, Uint32 length)
{
    Uint8 *psrc, *pdst;
    Uint32 i;

    /* Establish source and destination */
    psrc = (Uint8 *)src;
    pdst = (Uint8 *)dst; 
    for (i = 0; i < length; i++)
    {
        // Program one 8-bit word
        *((Uint8 *)EVMDM642_FLASH_BASE) = 0xaa;
        *((Uint8 *)EVMDM642_FLASH_BASE) = 0x55;
        *((Uint8 *)EVMDM642_FLASH_BASE) = 0xa0;
        *pdst = *psrc;
        
        // Wait for operation to complete
        while(1)
            if (*pdst == *psrc)
                break;
                
        pdst++;
        psrc++;
    }
    
    /* Put back in read mode */
    *((Uint16 *)EVMDM642_FLASH_BASE) = 0xf0;    
}


/* Constant table containing end address of each sector */
static Uint32 sector_end[EVMDM642_FLASH_SECTORS] = {
    EVMDM642_FLASH_BASE + 0x00ffff, /* Sector  0 */
    EVMDM642_FLASH_BASE + 0x01ffff, /* Sector  1 */
    EVMDM642_FLASH_BASE + 0x02ffff, /* Sector  2 */
    EVMDM642_FLASH_BASE + 0x03ffff, /* Sector  3 */
    EVMDM642_FLASH_BASE + 0x04ffff, /* Sector  4 */
    EVMDM642_FLASH_BASE + 0x05ffff, /* Sector  5 */
    EVMDM642_FLASH_BASE + 0x06ffff, /* Sector  6 */
    EVMDM642_FLASH_BASE + 0x07ffff  /* Sector  7 */
};


/* Erase a segment of Flash memory */
void EVMDM642_FLASH_erase(Uint32 start, Uint32 length)
{
    Int16 i;
    Uint8 *pdata;
    Uint32 sector_base, end;
    
    /* Calculate extents of range to erase */
    end = start + length - 1;
    
    /* Walk through each sector, erase any sectors within range */
    sector_base = EVMDM642_FLASH_BASE;
    for (i = 0; i < EVMDM642_FLASH_SECTORS; i++)
    {
        if ((start <= sector_base) && (sector_end[i] <= end))
        {
            /* Start sector erase sequence */
            *((Uint8 *)EVMDM642_FLASH_BASE) = 0xaa;
            *((Uint8 *)EVMDM642_FLASH_BASE) = 0x55;
            *((Uint8 *)EVMDM642_FLASH_BASE) = 0x80;
            *((Uint8 *)EVMDM642_FLASH_BASE) = 0xaa;
            *((Uint8 *)EVMDM642_FLASH_BASE) = 0x55;
            
            /* Start erase at sector address */
            pdata = (Uint8 *)sector_base;
            *pdata = 0x30;
            
            /* Wait for erase to complete */
            while (1)
                if (*pdata & 0x80)
                    break;
                    
            /* Put back in read mode */
            *((Uint8 *)EVMDM642_FLASH_BASE) = 0xf0;                    
        }
        
        /* Advance to next sector */
        sector_base = sector_end[i] + 1;
    }
}


/* Calculate the checksum of a data range in Flash */
Uint32 EVMDM642_FLASH_checksum(Uint32 start, Uint32 length)
{
    Int16 i;
    Uint8 *pdata;
    Uint32 checksum;
    
    /* Establish source and destination */
    pdata = (Uint8 *)start;
    
    /* Calculate checksum by adding each word to the total */
    checksum = 0;
    for (i = 0; i < length; i++)
    {
        checksum += *pdata++;
    }
    
    return checksum;
}


Int16 TEST_flashID()
{
    Uint8 MfgId,DevId;
    Int16 i;
    
    /* Reset flash */
    *((Uint8 *)EVMDM642_FLASH_BASE) = 0xf0;
 
    /* Configure to read manufacturer ID */
    *((Uint8 *)EVMDM642_FLASH_BASE) = 0xaa;
    *((Uint8 *)EVMDM642_FLASH_BASE) = 0x55;
    *((Uint8 *)EVMDM642_FLASH_BASE) = 0x90; 
    
    /* Insert small delay for device to respond */
    for (i = 0; i < 10; i++);

    /* Read IDs */
    MfgId = *((Uint8 *)EVMDM642_FLASH_BASE);
    DevId = *((Uint8 *)EVMDM642_FLASH_BASE + 1);

    /* Reset flash */
    *((Uint8 *)EVMDM642_FLASH_BASE) = 0xf0;

    /* Check IDs */
    if ((MfgId != 0x0001) || (DevId != 0xa3))
        return 1;

    /* Test passed */
    return 0;
}


/*
 *  Diagnostic utility specific tests
 */

Int16 TEST_flashall()
{
    Uint16 i, j, k, page, limit;
    Uint32 startaddr, addr;

    /* Program the Flash page by page, 256 words at a time */
    for (page = 0; page < 1; page++)
    {
        /* Set Flash page */
        EVMDM642_rset(EVMDM642_FLASHPAGE, page);
        
          /* Erase all of the Flash */
        EVMDM642_FLASH_erase(EVMDM642_FLASH_BASE, EVMDM642_FLASH_PAGESIZE);


        addr = EVMDM642_FLASH_BASE;
        if (page == 0)
            limit = 8;
        else
            limit = 1;
        for (i = 0; i < limit; i++)
        {
            for (j = 0; j < 128; j++)
            {
                startaddr = addr;
                for (k = 0; k < 256; k++)
                {
                    buffer[k] = addr + i + page;
                    addr += 2;
                }
                EVMDM642_FLASH_write((Uint32)buffer, startaddr, 512);
            }
        }
    }

    /* Verify the Flash page by page, 256 bytes at a time */
    for (page = 0; page < 8; page++)
    {
        /* Set Flash page */
        EVMDM642_rset(EVMDM642_FLASHPAGE, page);
        
        addr = EVMDM642_FLASH_BASE;
        if (page == 0)
            limit = 8;
        else
            limit = 1;
        for (i = 0; i < limit; i++)
        {
            for (j = 0; j < 128; j++)
            {
                startaddr = addr;
                EVMDM642_FLASH_read(startaddr, (Uint32)buffer, 512);
                for (k = 0; k < 256; k++)
                {
                    if (buffer[k] != ((addr + i + page) & 0xffff))
                        return page + 1;
                    addr += 2;
                }
            }
        }
    }

    return 0;
}



//End of File
